// @ts-ignore
window.__LIKIT_JS_BRIDGE_NAME__ = 'likitJSBridge';

function getBridge() {
  // 根据不同平台获取bridge并调用
  // @ts-ignore
  let bridge = window[window.__LIKIT_JS_BRIDGE_NAME__] || window.ReactNativeWebView;
  if (!bridge) {
    // @ts-ignore
    const windowWebkit = window.webkit;
    if (windowWebkit) {
      const { messageHandlers } = windowWebkit;
      if (messageHandlers) {
        // @ts-ignore
        bridge = messageHandlers[window.__LIKIT_JS_BRIDGE_NAME__] || messageHandlers.ReactNativeWebView;
      }
    }
  }
  return bridge;
}

function getBackBridgeName() {
  // @ts-ignore
  return window.__LIKIT_JS_BRIDGE_NAME__.replace('JSBridge', 'BackJSBridge');
}

;(() => {
  let id = 0;
  const callbacks: any = {};
  const functions: any = {};
  window[getBackBridgeName()] = {
    // @ts-ignore
    invoke(api: string, args: any, callback: any) {
      const bridge = getBridge();
      if (bridge) {
        // 自增id保持唯一性
        let thisCallbackID;
        // 存储回调函数
        if (callback) {
          thisCallbackID = (id += 1).toString();
          callbacks[thisCallbackID] = callback;
        } else {
          thisCallbackID = null;
        }
        // @ts-ignore
        bridge.postMessage(
          JSON.stringify({
            api,
            args: args || {},
            callbackID: thisCallbackID,
          }),
        );
      } else if (callback) {
        callback({
          success: false,
        });
      }
    },
    onInvoke(message: any) {
      const { api } = message;
      const args = message.args || {};
      const { callbackID } = message;
      let responseMessage;
      // 取出函数，callbackID必然要有，api不一定存在
      if (api) {
        const thisFunctions = functions[api];
        if (thisFunctions) {
          let responseArgs = {};
          let flag = false;
          thisFunctions.forEach((_callback: any) => {
            _callback(args, (_args: any) => {
              flag = true;
              responseArgs = Object.assign(responseArgs, _args);
            });
          });
          if (flag) {
            responseMessage = JSON.stringify({
              api,
              args: responseArgs,
              callbackID,
            });
            const bridge = getBridge();
            // @ts-ignore
            bridge.postMessage(responseMessage);
            return responseMessage;
          }
        }
      } else if (callbackID) {
        const thisFunction = callbacks[callbackID];
        if (thisFunction) {
          responseMessage = JSON.stringify(thisFunction(args) || {});
          delete callbacks[callbackID];
          return responseMessage;
        }
      }
      return undefined;
    },
    on(api: string, callback: any) {
      let thisFunctions = functions[api];
      if (!thisFunctions) {
        thisFunctions = [];
        functions[api] = thisFunctions;
      }
      thisFunctions.push(callback);
    },
    removeOn(api: string, callback: any) {
      const thisFunctions = functions[api];
      if (thisFunctions) {
        for (let i = 0, { length } = thisFunctions; i < length; i += 1) {
          if (thisFunctions[i] === callback) {
            thisFunctions.splice(i, 1);
            return true;
          }
        }
      }
      return false;
    },
    removeAllOn(api: string) {
      const thisFunctions = functions[api];
      if (thisFunctions) {
        thisFunctions.splice(0, thisFunctions.length);
        return true;
      }
      return false;
    },
  };
})();

function invoke(api: string, args: any, callback: any) {
  // @ts-ignore
  window[getBackBridgeName()].invoke(api, args, callback);
}

function on(api: string, callback: any) {
  // @ts-ignore
  window[getBackBridgeName()].on(api, callback);
}

function removeOn(api: string, callback: any) {
  // @ts-ignore
  window[getBackBridgeName()].removeOn(api, callback);
}

function removeAllOn(api: string) {
  // @ts-ignore
  window[getBackBridgeName()].removeAllOn(api);
}

function setBridgeName(identifier: string) {
  const backBridgeName = getBackBridgeName();
  // @ts-ignore
  const jsBridge = window[backBridgeName];
  // @ts-ignore
  window[backBridgeName] = undefined;
  // @ts-ignore
  delete window[backBridgeName];
  // @ts-ignore
  window.__LIKIT_JS_BRIDGE_NAME__ = `${identifier}JSBridge`;
  // @ts-ignore
  window[getBackBridgeName()] = jsBridge;
}

export { invoke, on, removeOn, removeAllOn, setBridgeName };
export default { invoke, on, removeOn, removeAllOn, setBridgeName };
